Many software systems are designed to work in conjunction with other software systems. Examples include application programs that work in conjunction with operating systems, network clients that work in conjunction with network servers, and telecommunications software packages that work in conjunction with host computer interfaces. In each of these pairs, one of the software systems provides services to the other software system. The software system providing the services is called the server. The software system receiving the services is called the client. The interface between client and server, called the Application Program interface (API), is typically implemented as a set of routines that a client calls. A developer of a server publishes a specification defining the input, output, and behavior of each API routine. Developers of clients use these specifications to develop clients that are compatible with the server.
Thus, a client is dependent on the behavior of its servers. When the server is modified in a way that changes its behavior (e.g., when a new version is released), behavior-dependent clients may be incompatible with the modified server and fail to work correctly. This failure is known as incompatibility failure.
Two kinds of modifications of servers constitute potential sources of incompatibility failure: bug corrections and enhancements. A bug correction is the modification of the behavior of an API routine that is inconsistent with the routine's specification. The inconsistency is generally the result of a programming error, or "bug." Server bug correction causes incompatibility failure when the client that calls the API routine is inconsistent with that routine's specification. This inconsistency can arise in two ways. First, the client could have originally been designed in a way inconsistent with the routine's specification. However, the server bug could have prevented discovery of the inconsistency of the client during testing. When the server bug is corrected, the server becomes consistent with the specification, while the client remains inconsistent. Second, the client could have originally been designed in a way consistent with the routine's specification. When the consistent client fails during testing because of the server bug, the client would be redesigned to work with the server bug. After redesign, the client would no longer be consistent with the routine's specification, and thus would not work with the server.
Server bug correction is needed when the behavior of the server is inconsistent with its specification. An example of server bug correction capable of causing an incompatibility failure is the removal of code that translates text returned to clients into uppercase. The server's specification calls for the server to copy some text returned to clients from external sources without regard for case. Since text returned by the server had formerly contained only uppercase text, some clients were built without the ability to parse lowercase text. When the code for translating into uppercase is removed from the server, these clients fail.
The second kind of modification of the server that might cause an incompatibility failure is an enhancement. An enhancement can change the inputs, outputs, or behavior of an API routine. Server developers usually make every effort to make enhancements backward compatible. However, this is sometimes impossible. If the enhanced server is not backward compatible, incompatibility failure results.
An example of a server enhancement capable of causing an incompatibility failure is the addition of code that determines whether the server actually needs to send the client a certain message and omits sending the message when it is not needed. The old server sent clients a message requesting the recalculation of a window's size each time the window moved, as well as when the window was resized. Since recalculation is not necessary when the window simply moves, a server enhancement causing the server to omit sending this message in response to a window move introduces greater efficiency. This enhancement results in an incompatibility failure with some clients that do more than recalculate window size in response to this message.
Both kinds of modifications involve replacing old steps with new steps. When this happens, an old server becomes a new server. FIG. 1A is a flow diagram showing a portion of an old server, corresponding to a single API routine. FIG. 1B is a flow diagram of the same API routine after modification. FIG. 1A shows that the old client routine consists of steps 101-152. FIG. 1B shows that, in the new server routine, steps 101-150 remain intact, and that old steps 151-152 are replaced with new steps 161-163. If the old steps provide an old behavior upon which any clients are dependent, and the new steps fail to provide that behavior, incompatibility failure will result. In such cases, the new steps are known as incompatible steps.
In order to avoid an incompatibility failure, some new servers perform their old behaviors for the benefit of certain clients. Developers typically include substantially all of the code for one or more earlier versions of the server along with a new version of the server. For clients that are dependent on behaviors of an earlier version, the server executes all of the code for that earlier version instead of the code for the new version.
FIGS. 2A-2B are flow diagrams that illustrate this approach. FIG. 2A is a flow diagram of an old server. The old server consists of old steps 202-249. FIG. 2B is a flow diagram of a new server. In step 250, the server determines the version of the server for which a client was developed. If the client was developed for the old version, then the server executes old code steps 202-249, else the server executes new code steps 252-299.
This approach has shortcomings. First, it causes the size of the code to grow very quickly, making the code more difficult and more expensive to maintain, transport, and store. Second, this approach deprives clients that are incompatible with an isolated new behavior of all of the enhancements and bug corrections of the new version not related to that new behavior.